"""
http server v2.0
env: python 3.10
IO多路复用 , http训练
"""

from socket import *  # 网络套接字
from select import *  # IO多路复用模块
import sys

# 具体功能实现
class HTTPServer:
    def __init__(self, ADDR=("0.0.0.0",18693), DIR='./static'):
        # 初始化select的监控列表
        self.__rlist = []
        self.__wlist = []
        self.__xlist = []
        self.__DIR = DIR   # 网页存放的位置
        
        # 初始化套接字
        self.__ADDR = ADDR
        self.__sockfd = socket()
        self.__sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
        self.__sockfd.bind(self.__ADDR)
        
    # main
    def server_forever(self):
        self.__sockfd.listen(5)
        print("服务启动成功: ", self.__ADDR)
        
        # 搭建IO多路复用,监控各种IO请求
        self.__rlist.append(self.__sockfd)  # 将当前套接字追加到读列表
        while True:
            rs, ws, xs = select(self.__rlist, self.__wlist, self.__xlist)
            for r in rs:
                # 浏览器连接进来
                if r is self.__sockfd:
                    c, addr = r.accept()
                    self.__rlist.append(c) # 将当前链接追加到列表中
                else:
                    # 处理客户端请求
                    self.__hand le(r) # 传入当前链接
    
    # 处理客户端请求
    def __handle(self, r):
        # 接收http请求
        request = r.recv(4096)
        
        # 客户端断开
        if not request:
            self.__rlist.remove(r) # 删除当前链接
            r.close() # 关闭当前服务
            return

        # 提起请求内容 (将字节串按行切割)
        re_line = request.splitlines()[0] # splitlines是将字节串按行切割,提取出(b'GET / HTTP/1.1')
        info = re_line.decode().split(' ')[1] # 将 b'GET /(请求体文件名字) HTTP/1.1' 中的请求体第一个 / 提取出来
        print(f"请求内容 {c.getpeername} : {info}")
        
        # 根据请求内容进行数据整理
        # 分为两类: 1. 请求网页,2. 其他(资源, 文件等等)
        if info == '/' or info[-5:] == '.html': # info[-5:] 等于 b'GET /index.html HTTP/1.1' 中的 .html 这5个字符
            self.__get_html(r, info) # 传入当前链接和请求内容
        else:
            self.__get_data(r, info)
            
    # 处理网页
    def __get_html(self,  connfd, info):
        if info == '/':
            # 请求主页
            # lc = sys.path[0] + "\\index.html"  # 此路径问题只出现在vs code上, python和pycharm都没有问题, 删掉即可
            filename = sys.path[0] + self.__DIR + "\\index.html"
            print(filename)
        else:
            filename = self.__DIR + info
        
        # 打开网页
        try:
            fd = open(filename, 'rb', encoding="utf-8")
        except Exception: # 网页不存在
            response = "HTTP/1.1 404 未找到!\r\nContent-Type:text/html\r\n\r\n<h1>bao qian...</h1>"
        else:  # 否则找到该网页,读取出来
            response = "HTTP/1.1 200 ok\r\nContent-Type:text/html\r\n\r\n"
            response += fd.read()
        finally: # 发生网页
            connfd.send(response.encode())
            
    
    # 处理其他
    def __get_data(self,connfd, info):
        f = open(self.__DIR + "/time.jpg", 'rb', encoding="utf-8")
        data = f.read()
        response = "HTTP/1.1 200 ok\r\nContent-Type:image/jpeg\r\n\r\n"
        response = response.encode() + data
        connfd.send(response)
        
        

# 用户应该怎么用HTTPServer
if __name__ == "__main__":
    """
    通过HTTPServer快速启动服务,用于展示自己的网页
    """
    # 客户决定的参数
    ADDR = ('182.61.145.239', 18693) # 182.61.145.239
    
    # 客户网页存储的位置
    DIR = './static'
    
    httpd = HTTPServer(ADDR, DIR) # 实例化对象
    httpd.server_forever() # 启动服务
    
    